{%-import 'constraints.jinja2' as constraint-%}
{%-if schema.type == 'integer'%}{%-set rjtype = 'int'%}{%-else%}{%-set rjtype = 'number'%}{%-endif-%}
{%-if schema.type == 'integer'%}{%-set cpptype = 'int'%}{%-else%}{%-set cpptype = 'double'%}{%-endif%}
{%-set std = resolver.cpp_resolve_namespace(['std']) %}
{%-set className = resolver.cpp_resolve_namespace(ns)+Name%}
{%-set exception %}{{resolver.cpp_get_lib_ns() | join('::')}}::JsonSchemaException{%endset%}
{%if schema.const is not defined%}
{{className}}::{{Name}}({{cpptype}} value)
{
    Set(value);
}
{%endif%}
{%-if schema.default is defined or schema.const is defined%}
{%set emptyConstructor = true %}
{{className}}::{{Name}}()
{
    Set({%-if schema.const is defined-%}{{constraint.ExprName('const')}}{%-else-%}{{constraint.ExprName('default')}}{%-endif-%});
}
{%-endif%}

{{className}}::operator {{cpptype}}() const
{
    return Get();
}

{{className}}& {{className}}::operator=({{cpptype}} value)
{
    Set(value);
    return *this;
}
{%for origNs in originalNamespace %}
namespace {{origNs}} {
{%-endfor%} 
{{std}}ostream& operator<<({{std}}ostream& os, const {{className}}& num)
{
    os << num._value;
    return os;
}

bool operator< (const {{className}}& left, const {{className}}& right)
{
    return left._value < right._value;
}

{{std}}size_t hash_value(const {{className}}& num)
{
    return boost::hash_value(num._value);
}
{%for origNs in originalNamespace %}}{%-endfor%} // end namespaces

{{className}}& {{className}}::Set({{cpptype}} value)
{
    Validate(value);
    _value = value;
    return *this;
}

{{cpptype}} {{className}}::Get() const
{
    return _value;
}

void {{className}}::Validate({{cpptype}} testValue)
{
    {%-if schema.minimum is defined %}
    if (testValue < {{constraint.ExprName('minimum')}}) throw {{exception}}("Value was less than {{schema.minimum}}");
    {%-endif%}
    {%-if schema.exclusiveMinimum is defined %}
    if (testValue <= {{constraint.ExprName('exclusiveMinimum')}}) throw {{exception}}("Value was less than or equal to {{schema.exclusiveMinimum}}");
    {%-endif%}
    {%-if schema.maximum is defined %}
    if (testValue > {{constraint.ExprName('maximum')}}) throw {{exception}}("Value was more than {{schema.maximum}}");
    {%-endif%}
    {%-if schema.exclusiveMaximum is defined %}
    if (testValue >= {{constraint.ExprName('exclusiveMaximum')}}) throw {{exception}}("Value was less than or equal to {{schema.exclusiveMaximum}}");
    {%-endif%}
    {%-if schema.multipleOf is defined %}
    if ((testValue % {{constraint.ExprName('multipleOf')}}) != 0) throw {{exception}}("Value was less than or equal to {{schema.exclusiveMaximum}}");
    {%-endif%}
    {%-if schema.const is defined%}
    if (testValue != {{constraint.ExprName('const')}}) throw {{exception}}("Value was not {{schema.const}}");
    {%-endif%}
}

{{className}} {{className}}::FromJson(const {{resolver.cpp_resolve_namespace(['rapidjson'])}}Value& json)
{
    if (!(json.Is{{rjtype | UpperCamelCase}}()))
    {
        throw {{exception}}("Wasn't a {{rjtype}}");
    }

    {{className}} newObject(json.Get{{cpptype | UpperCamelCase}}());
    return newObject;
}

{{className}} {{className}}::FromString(const {{std}}string& str)
{
    return {{className}}({{resolver.cpp_resolve_namespace(['boost'])}}lexical_cast<{{cpptype}}>(str));
}

void {{className}}::ToJson({{resolver.cpp_resolve_namespace(['rapidjson'])}}Value& value, {{resolver.cpp_resolve_namespace(['rapidjson', 'Value'])}}AllocatorType& allocator) const
{
    value.Set{{cpptype | UpperCamelCase}}(_value); 
}

void {{className}}::SetHandle(const std::string& handle)
{
    _handle = handle;
}

std::string {{className}}::GetHandle() const
{
    return _handle;
}